package com.horsecoder.im.common.handler;

import com.google.gson.Gson;
import com.horsecoder.common.error.Assert;
import com.horsecoder.common.status.StatusException;
import com.horsecoder.im.common.protocol.action.handler.ActionDispatcherHandler;
import com.horsecoder.im.common.protocol.action.handler.Handler;
import com.horsecoder.im.common.protocol.context.SessionSocketHolder;
import com.horsecoder.im.common.protocol.context.chain.request.Request;
import com.horsecoder.im.common.protocol.context.chain.response.Response;
import com.horsecoder.im.common.protocol.convert.Converter;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;

/**
 * WebSocket协议输入解码Handler
 * <p>
 * Author: Zhu yuhan
 * Email: zhuyuhan2333@qq.com
 * Date: 2022/3/16 11:11 上午
 **/
public class HorsecoderImWebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> implements Converter<ByteBuf, Request> {

    private final Handler dispatch = new ActionDispatcherHandler();

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame) {
        ByteBuf content = webSocketFrame.content();
        Request request = convert(content);
        String identity = request.getIdentity();
        String receiver = request.getReceiver();
        Assert.isTrue(!StringUtils.isEmpty(identity) && !StringUtils.isEmpty(receiver), "IDENTITY_ERROR");
        SessionSocketHolder.putSocketChannel(identity, channelHandlerContext.channel());
        Response response = new Response(request);
        // TODO: 2022/3/17 心跳保活
        Channel channel = SessionSocketHolder.getChannelByIdentity(channelHandlerContext);
        Assert.notNull(channel, "SOCKET_ERROR");
        dispatch.handle(SessionSocketHolder.getSocketChannel(receiver), request, response);
    }

    @Override
    public Request convert(ByteBuf byteBuf) {
        try {
            return new Gson().fromJson(byteBuf.toString(StandardCharsets.UTF_8), Request.class);
        } catch (Exception e) {
            throw new StatusException("MESSAGE_ERROR");
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        SessionSocketHolder.putChannelIdentity(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        SessionSocketHolder.removeChannelByIdentity(ctx);
    }
}
